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/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/errno.h> 34 #include <sys/lock.h> 35 #include <sys/mutex.h> 36 #include <sys/sysctl.h> 37 #include <sys/syslog.h> 38 #include <sys/bus.h> 39 40 #include <machine/bus.h> 41 #include <sys/rman.h> 42 #include <machine/resource.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcireg.h> 45 46 #define PCHTHERM_REG_TEMP 0 47 #define PCHTHERM_REG_TSC 4 48 #define PCHTHERM_REG_TSS 6 49 #define PCHTHERM_REG_TSEL 8 50 #define PCHTHERM_REG_TSREL 0xa 51 #define PCHTHERM_REG_TSMIC 0xc 52 #define PCHTHERM_REG_CTT 0x10 53 #define PCHTHERM_REG_TAHV 0x14 54 #define PCHTHERM_REG_TALV 0x18 55 #define PCHTHERM_REG_TSPM 0x1c 56 #define PCHTHERM_REG_TL 0x40 57 #define PCHTHERM_REG_TL2 0x50 58 #define PCHTHERM_REG_PHL 0x60 59 #define PCHTHERM_REG_PHLC 0x62 60 #define PCHTHERM_REG_TAS 0x80 61 #define PCHTHERM_REG_TSPIEN 0x82 62 #define PCHTHERM_REG_TSGPEN 0x84 63 #define PCHTHERM_REG_TCFD 0xf0 64 #define PCHTHERM_GEN_LOCKDOWN 0x80 65 #define PCHTHERM_GEN_ENABLE 1 66 #define PCHTHERM_TEMP_FACTOR 5 67 #define PCHTHERM_TEMP_ZERO 2231 68 #define PCHTHERM_TEMP_MASK 0x1ff 69 #define PCHTHERM_TL_T0 0 70 #define PCHTHERM_TL_T1 10 71 #define PCHTHERM_TL_T2 20 72 #define PCHTHERM_TEMP_TO_IK(val) (((val) & PCHTHERM_TEMP_MASK) * \ 73 PCHTHERM_TEMP_FACTOR + \ 74 PCHTHERM_TEMP_ZERO) 75 76 struct pchtherm_softc 77 { 78 int tbarrid; 79 struct resource *tbar; 80 int enable; 81 int ctten; 82 int pmtemp; 83 unsigned int pmtime; 84 }; 85 86 static const struct pci_device_table pchtherm_devices[] = 87 { 88 { PCI_DEV(0x8086, 0x9c24), 89 PCI_DESCR("Haswell Thermal Subsystem")}, 90 { PCI_DEV(0x8086, 0x8c24), 91 PCI_DESCR("Haswell Thermal Subsystem")}, 92 { PCI_DEV(0x8086, 0x9ca4), 93 PCI_DESCR("Wildcat Point Thermal Subsystem")}, 94 { PCI_DEV(0x8086, 0x9d31), 95 PCI_DESCR("Skylake PCH Thermal Subsystem")}, 96 { PCI_DEV(0x8086, 0xa131), 97 PCI_DESCR("Skylake PCH 100 Thermal Subsystem")}, 98 { PCI_DEV(0x8086, 0x9df9), 99 PCI_DESCR("Cannon Lake PCH Thermal Controller")}, 100 }; 101 102 static int pchtherm_probe(device_t dev) 103 { 104 const struct pci_device_table *tbl; 105 106 tbl = PCI_MATCH(dev, pchtherm_devices); 107 if (tbl == NULL) 108 return (ENXIO); 109 device_set_desc(dev, tbl->descr); 110 111 return (BUS_PROBE_DEFAULT); 112 113 } 114 static int pchtherm_tltemp_sysctl(SYSCTL_HANDLER_ARGS) 115 { 116 struct pchtherm_softc *sc = oidp->oid_arg1; 117 int regshift = oidp->oid_arg2; 118 int temp; 119 120 temp = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 121 temp >>= regshift; 122 temp = PCHTHERM_TEMP_TO_IK(temp); 123 124 return sysctl_handle_int(oidp, &temp, 0, req); 125 } 126 static int pchtherm_temp_sysctl(SYSCTL_HANDLER_ARGS) 127 { 128 struct pchtherm_softc *sc = oidp->oid_arg1; 129 int regoff = oidp->oid_arg2; 130 int temp; 131 132 temp = bus_read_2(sc->tbar, regoff); 133 temp = PCHTHERM_TEMP_TO_IK(temp); 134 135 return sysctl_handle_int(oidp, &temp, 0, req); 136 } 137 138 #define FLAG_PRINT(dev, str, val) device_printf \ 139 (dev, str " %s %sable\n", \ 140 ((val) & 0x80)? "Locked" : "", \ 141 ((val) & 0x1)? "En" : "Dis") 142 143 static int pchtherm_attach(device_t dev) 144 { 145 struct pchtherm_softc *sc = device_get_softc(dev); 146 unsigned int val; 147 int flag; 148 int temp; 149 150 sc->tbarrid = PCIR_BAR(0); 151 sc->tbar = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 152 &sc->tbarrid, RF_ACTIVE|RF_SHAREABLE); 153 if (sc->tbar == NULL) { 154 return (ENOMEM); 155 } 156 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 157 if (!(sc->enable & PCHTHERM_GEN_ENABLE )) { 158 if (sc->enable & PCHTHERM_GEN_LOCKDOWN) { 159 device_printf(dev, "Sensor not available\n"); 160 return 0; 161 } else { 162 device_printf(dev, "Enabling Sensor\n"); 163 bus_write_1(sc->tbar, PCHTHERM_REG_TSEL, 164 PCHTHERM_GEN_ENABLE); 165 sc->enable = bus_read_1(sc->tbar, PCHTHERM_REG_TSEL); 166 if (!(sc->enable & PCHTHERM_REG_TSEL)){ 167 device_printf(dev, "Sensor enable failed\n"); 168 return 0; 169 } 170 } 171 } 172 173 sc->ctten = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); 174 if (bootverbose) { 175 FLAG_PRINT(dev, "Catastrophic Power Down", sc->ctten); 176 } 177 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSREL); 178 if (bootverbose) { 179 FLAG_PRINT(dev, "SMBus report", val); 180 } 181 val = bus_read_1(sc->tbar, PCHTHERM_REG_TSC); 182 if (bootverbose) { 183 FLAG_PRINT(dev, "SMI on alert", val); 184 } 185 val = bus_read_2(sc->tbar, PCHTHERM_REG_TSPM); 186 flag = val >> 13; 187 if (bootverbose) { 188 device_printf(dev, "TSPM: %b\n", 189 flag, "\20\3Lock\2DTSS0EN\1DSSOC0"); 190 device_printf(dev, "MAX Thermal Sensor Shutdown Time %ds\n", 191 1<<((val>>9)&7)); 192 } 193 194 temp = val & PCHTHERM_TEMP_MASK; 195 sc->pmtemp = PCHTHERM_TEMP_TO_IK(temp); 196 sc->pmtime = 1<<((val>>9)&7); 197 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 198 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 199 OID_AUTO, "pmtemp", CTLTYPE_INT|CTLFLAG_RD, 200 sc, PCHTHERM_REG_TSPM, pchtherm_temp_sysctl, 201 "IK", "Thermal sensor idle temperature"); 202 SYSCTL_ADD_U32(device_get_sysctl_ctx(dev), 203 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 204 OID_AUTO, "pmtime", CTLFLAG_RD, 205 &sc->pmtime, 0,"Thermal sensor idle duration"); 206 207 val = bus_read_4(sc->tbar, PCHTHERM_REG_TL); 208 flag = val>>29; 209 210 if (bootverbose) { 211 device_printf(dev, "Throttling %b\n", 212 flag, "\20\3Lock\2TT13EN\1TTEN"); 213 } 214 215 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 216 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 217 OID_AUTO, "t0temp", CTLTYPE_INT |CTLFLAG_RD, 218 sc, PCHTHERM_TL_T0, pchtherm_tltemp_sysctl, 219 "IK", "T0 temperature"); 220 221 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 222 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 223 OID_AUTO, "t1temp", CTLTYPE_INT |CTLFLAG_RD, 224 sc, PCHTHERM_TL_T1, pchtherm_tltemp_sysctl, 225 "IK", "T1 temperature"); 226 227 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 228 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 229 OID_AUTO, "t2temp", CTLTYPE_INT |CTLFLAG_RD, 230 sc, PCHTHERM_TL_T2, pchtherm_tltemp_sysctl, 231 "IK", "T2 temperature"); 232 233 val = bus_read_2(sc->tbar, PCHTHERM_REG_TL2); 234 if (bootverbose) { 235 flag = val >>14; 236 device_printf(dev, "TL2 flag %b\n", 237 flag, "\20\1PMCTEN\2Lock"); 238 } 239 240 /* If PHL is disable and lockdown, don't export it.*/ 241 val = bus_read_2(sc->tbar, PCHTHERM_REG_PHLC); 242 val <<= 16; 243 val |= bus_read_2(sc->tbar, PCHTHERM_REG_PHL); 244 if ((val & 0x10000) != 0x10000) { 245 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 246 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 247 OID_AUTO, "pch_hot_level", 248 CTLTYPE_INT |CTLFLAG_RD, 249 sc, PCHTHERM_REG_PHL, 250 pchtherm_temp_sysctl, "IK", 251 "PCH Hot level Temperature"); 252 } 253 254 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 255 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 256 OID_AUTO, "temperature", CTLTYPE_INT |CTLFLAG_RD, 257 sc, PCHTHERM_REG_TEMP, 258 pchtherm_temp_sysctl, "IK", "Current temperature"); 259 /* 260 * If sensor enable bit is locked down, there is no way to change 261 * alart values effectively. 262 */ 263 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 264 bus_read_2(sc->tbar, PCHTHERM_REG_TAHV) != 0) { 265 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 266 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 267 OID_AUTO, "tahv", CTLTYPE_INT |CTLFLAG_RD, 268 sc, PCHTHERM_REG_TAHV, 269 pchtherm_temp_sysctl, "IK", 270 "Alart High temperature"); 271 } 272 273 if (!(sc->enable & PCHTHERM_GEN_LOCKDOWN) || 274 bus_read_2(sc->tbar, PCHTHERM_REG_TALV) != 0) { 275 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 276 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 277 OID_AUTO, "talv", CTLTYPE_INT |CTLFLAG_RD, 278 sc, PCHTHERM_REG_TALV, 279 pchtherm_temp_sysctl, "IK", 280 "Alart Low temperature"); 281 } 282 if (!(sc->ctten& PCHTHERM_GEN_LOCKDOWN) || 283 sc->ctten& PCHTHERM_GEN_ENABLE) { 284 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 285 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 286 OID_AUTO, "ctt", 287 CTLTYPE_INT |CTLFLAG_RD, 288 sc, PCHTHERM_REG_CTT, 289 pchtherm_temp_sysctl, "IK", 290 "Catastrophic Trip Point"); 291 } 292 293 return 0; 294 } 295 static int pchtherm_detach(device_t dev) 296 { 297 struct pchtherm_softc *sc = device_get_softc(dev); 298 bus_release_resource(dev, SYS_RES_MEMORY, sc->tbarrid, sc->tbar); 299 300 return 0; 301 } 302 static device_method_t pchtherm_methods[] = 303 { 304 DEVMETHOD(device_probe, pchtherm_probe), 305 DEVMETHOD(device_attach, pchtherm_attach), 306 DEVMETHOD(device_detach, pchtherm_detach), 307 308 DEVMETHOD_END 309 }; 310 static driver_t pchtherm_driver = { 311 "pchtherm", 312 pchtherm_methods, 313 sizeof(struct pchtherm_softc) 314 }; 315 316 static devclass_t pchtherm_devclass; 317 DRIVER_MODULE(pchtherm, pci, pchtherm_driver, pchtherm_devclass, 0, 0); 318 PCI_PNP_INFO(pchtherm_devices); 319