diff options
author | Robert Mustacchi <rm@joyent.com> | 2019-04-24 03:05:13 +0000 |
---|---|---|
committer | Robert Mustacchi <rm@joyent.com> | 2019-06-27 01:29:11 +0000 |
commit | dc90e12310982077796c5117ebfe92ee04b370a3 (patch) | |
tree | 7266c72ef469a9b7ce15389286cd9ffb6bdab119 | |
parent | 2d6125aab2c7deca41a7689dae14eb32ec909f49 (diff) | |
download | illumos-gate-dc90e12310982077796c5117ebfe92ee04b370a3.tar.gz |
11273 Want Intel PCH temperature sensor
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Mike Zeller <mike.zeller@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Gergő Doma <domag02@gmail.com>
Reviewed by: Paul Winder <Paul.Winder@wdc.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
-rw-r--r-- | usr/src/lib/fm/topo/libtopo/common/hc.c | 3 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/libtopo/common/topo_hc.h | 3 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml | 5 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/i86pc/Makefile | 2 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/i86pc/chipset/Makefile | 29 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/i86pc/chipset/chipset.c | 190 | ||||
-rw-r--r-- | usr/src/man/man7d/Makefile | 3 | ||||
-rw-r--r-- | usr/src/man/man7d/pchtemp.7d | 69 | ||||
-rw-r--r-- | usr/src/pkg/manifests/driver-cpu-sensor.mf | 12 | ||||
-rw-r--r-- | usr/src/pkg/manifests/service-fault-management.mf | 2 | ||||
-rw-r--r-- | usr/src/uts/common/sys/sunddi.h | 3 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.files | 7 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.intel | 3 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.rules | 4 | ||||
-rw-r--r-- | usr/src/uts/intel/io/pchtemp/pchtemp.c | 525 | ||||
-rw-r--r-- | usr/src/uts/intel/pchtemp/Makefile | 46 |
16 files changed, 898 insertions, 8 deletions
diff --git a/usr/src/lib/fm/topo/libtopo/common/hc.c b/usr/src/lib/fm/topo/libtopo/common/hc.c index 9c64077549..15d7b769e9 100644 --- a/usr/src/lib/fm/topo/libtopo/common/hc.c +++ b/usr/src/lib/fm/topo/libtopo/common/hc.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #include <stdio.h> @@ -154,6 +154,7 @@ static const hcc_t hc_canon[] = { { CENTERPLANE, TOPO_STABILITY_PRIVATE }, { CHASSIS, TOPO_STABILITY_PRIVATE }, { CHIP, TOPO_STABILITY_PRIVATE }, + { CHIPSET, TOPO_STABILITY_PRIVATE }, { CHIP_SELECT, TOPO_STABILITY_PRIVATE }, { CORE, TOPO_STABILITY_PRIVATE }, { CONTROLLER, TOPO_STABILITY_PRIVATE }, diff --git a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h index 26b307a20c..addc96803f 100644 --- a/usr/src/lib/fm/topo/libtopo/common/topo_hc.h +++ b/usr/src/lib/fm/topo/libtopo/common/topo_hc.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _TOPO_HC_H @@ -42,6 +42,7 @@ extern "C" { #define CENTERPLANE "centerplane" #define CHASSIS "chassis" #define CHIP "chip" +#define CHIPSET "chipset" #define CORE "core" #define STRAND "strand" #define CHIP_SELECT "chip-select" diff --git a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml index dc37ecfed4..0ddcd1e0d8 100644 --- a/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml +++ b/usr/src/lib/fm/topo/maps/i86pc/i86pc-legacy-hc-topology.xml @@ -2,7 +2,7 @@ <!DOCTYPE topology SYSTEM "/usr/share/lib/xml/dtd/topology.dtd.1"> <!-- Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. -Copyright (c) 2018, Joyent, Inc. All rights reserved. +Copyright 2019 Joyent, Inc. CDDL HEADER START @@ -86,6 +86,9 @@ Copyright (c) 2018, Joyent, Inc. All rights reserved. <range name='usb-mobo' min='0' max='100'> <enum-method name='usb' version='1' /> </range> + <range name='chipset' min='0' max='100'> + <enum-method name='chipset' version='1' /> + </range> </dependents> </range> diff --git a/usr/src/lib/fm/topo/modules/i86pc/Makefile b/usr/src/lib/fm/topo/modules/i86pc/Makefile index f42af0a306..36c4ea5f95 100644 --- a/usr/src/lib/fm/topo/modules/i86pc/Makefile +++ b/usr/src/lib/fm/topo/modules/i86pc/Makefile @@ -24,7 +24,7 @@ # Use is subject to license terms. # -SUBDIRS = chip hostbridge pcibus x86pi +SUBDIRS = chip chipset hostbridge pcibus x86pi .PARALLEL: $(SUBDIRS) diff --git a/usr/src/lib/fm/topo/modules/i86pc/chipset/Makefile b/usr/src/lib/fm/topo/modules/i86pc/chipset/Makefile new file mode 100644 index 0000000000..cd8c8761f7 --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/chipset/Makefile @@ -0,0 +1,29 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +MODULE = chipset +ARCH = i86pc +CLASS = arch +SHAREDDIR = ../../common/shared/ + +MODULESRCS = chipset.c topo_sensor.c + +include ../../Makefile.plugin + +CPPFLAGS += -I$(SHAREDDIR) + +%.o: $(SHAREDDIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) diff --git a/usr/src/lib/fm/topo/modules/i86pc/chipset/chipset.c b/usr/src/lib/fm/topo/modules/i86pc/chipset/chipset.c new file mode 100644 index 0000000000..cc306b4b2f --- /dev/null +++ b/usr/src/lib/fm/topo/modules/i86pc/chipset/chipset.c @@ -0,0 +1,190 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Joyent, Inc. + */ + +/* + * Chipset Enumeration + * + * Most x86 systems have some form of chipset which are components that exist on + * the motherboard that provide additional services that range from I/O such as + * memory and PCIe controllers (though as of this writing those mostly are a + * part of the CPU now) to additional functionality like Ethernet and USB + * controllers. At the moment, this module opts to enumerate a chipset node if + * there's something that exists under it that we care about such as: + * + * o Temperature sensors + * o Firmware modules + * + * If we do not detect anything, then we do not bother enumerating and trying to + * determine the different chipsets that are on the system. Currently, the only + * method for doing this is the presence of an Intel platform controller hub + * (PCH) temperature sensor. + */ + +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +#include <sys/fm/protocol.h> +#include <fm/topo_mod.h> +#include <fm/topo_list.h> +#include <fm/topo_method.h> + +#include <topo_sensor.h> + +#define CHIPSET_VERSION 1 + +/* + * This is the path to the temperature sensor that, if present, indicates we + * should construct a chipset node. + */ +static const char *topo_chipset_temp_sensor = + "/dev/sensors/temperature/pch/ts.0"; + +/* + * Attempt to determine if there is enough information for us to enumerate a + * chipset node, which usually means that we would enumerate something under it + * such as a temperature sensor or provide information about some piece of + * firmware that it has. Currently, if there is no temperature sensor, then we + * don't consider one to be present and don't do anything else. + */ +static boolean_t +topo_chipset_present(void) +{ + struct stat st; + + if (stat(topo_chipset_temp_sensor, &st) == 0 && + S_ISCHR(st.st_mode)) { + return (B_TRUE); + } + + return (B_FALSE); +} + +static int +topo_chipset_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, + topo_instance_t min, topo_instance_t max, void *modarg, void *data) +{ + int ret; + nvlist_t *fmri = NULL, *auth = NULL, *presource = NULL; + tnode_t *tn = NULL; + const topo_instance_t inst = 0; + + topo_mod_dprintf(mod, "chipset_enum: asked to enumerate %s", name); + + if (strcmp(name, CHIPSET) != 0) { + topo_mod_dprintf(mod, "chipset_enum: asked to enumerate " + "unknown component"); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + if (!topo_chipset_present()) { + topo_mod_dprintf(mod, "chipset_enum: no device present", name); + return (0); + } + + if ((auth = topo_mod_auth(mod, pnode)) == NULL) { + topo_mod_dprintf(mod, "chipset_enum: failed to get topo " + "auth: %s", topo_mod_errmsg(mod)); + /* topo_mod_auth() sets the module error */ + ret = -1; + goto err; + } + + if ((fmri = topo_mod_hcfmri(mod, pnode, FM_HC_SCHEME_VERSION, + CHIPSET, inst, NULL, auth, NULL, NULL, NULL)) == NULL) { + topo_mod_dprintf(mod, "chipset_enum: failed to get FMRI: %s", + topo_mod_errmsg(mod)); + /* topo_mod_hcfmri() sets the module error */ + ret = -1; + goto err; + } + + if ((tn = topo_node_bind(mod, pnode, CHIPSET, inst, fmri)) == NULL) { + topo_mod_dprintf(mod, "chipset_enum: failed to bind node: %s", + topo_mod_errmsg(mod)); + ret = -1; + goto err; + } + + if (topo_node_resource(pnode, &presource, &ret) != 0) { + topo_mod_dprintf(mod, "chipset_enum: failed to get parent " + "resource %s\n", topo_strerror(ret)); + ret = topo_mod_seterrno(mod, ret); + goto err; + } + + if (topo_node_fru_set(tn, presource, 0, &ret) != 0) { + topo_mod_dprintf(mod, "chipset_enum: failed to set FRU: %s", + topo_strerror(ret)); + ret = topo_mod_seterrno(mod, ret); + goto err; + } + + /* + * Finally, create the temperature sensor. + */ + if ((ret = topo_sensor_create_temp_sensor(mod, tn, + topo_chipset_temp_sensor, "temp")) != 0) { + topo_mod_dprintf(mod, "failed to create chipset temperature " + "sensor"); + goto err; + } + + nvlist_free(auth); + nvlist_free(fmri); + nvlist_free(presource); + return (0); +err: + nvlist_free(auth); + nvlist_free(fmri); + nvlist_free(presource); + topo_node_unbind(tn); + return (ret); +} + +static const topo_modops_t chipset_ops = { + topo_chipset_enum, NULL +}; + +static topo_modinfo_t chipset_mod = { + CHIPSET, FM_FMRI_SCHEME_HC, CHIPSET_VERSION, &chipset_ops +}; + +int +_topo_init(topo_mod_t *mod, topo_version_t version) +{ + if (getenv("TOPOCHIPSETDEBUG") != NULL) { + topo_mod_setdebug(mod); + } + + topo_mod_dprintf(mod, "_mod_init: initializing %s enumerator\n", + CHIPSET); + + if (version != -1) { + + } + + if (topo_mod_register(mod, &chipset_mod, TOPO_VERSION) != 0) { + return (-1); + } + + return (0); +} + +void +_topo_fini(topo_mod_t *mod) +{ +} diff --git a/usr/src/man/man7d/Makefile b/usr/src/man/man7d/Makefile index ceec9a8978..3f0523b84a 100644 --- a/usr/src/man/man7d/Makefile +++ b/usr/src/man/man7d/Makefile @@ -12,7 +12,7 @@ # # Copyright 2011, Richard Lowe # Copyright 2016 Garrett D'Amore <garrett@damore.org> -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> # Copyright 2018 Nexenta Systems, Inc. # Copyright 2019 Peter Tribble @@ -217,6 +217,7 @@ i386_MANFILES= ahci.7d \ ntxn.7d \ nv_sata.7d \ nvme.7d \ + pchtemp.7d \ pcn.7d \ qede.7d \ ral.7d \ diff --git a/usr/src/man/man7d/pchtemp.7d b/usr/src/man/man7d/pchtemp.7d new file mode 100644 index 0000000000..d89f09ab90 --- /dev/null +++ b/usr/src/man/man7d/pchtemp.7d @@ -0,0 +1,69 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2019 Joyent, Inc. +.\" +.Dd April 26, 2019 +.Dt PCHTEMP 7D +.Os +.Sh NAME +.Nm pchtemp +.Nd Intel platform controller hub temperature sensor driver +.Sh SYNOPSIS +.Pa /dev/sensors/temperature/pch/* +.Sh DESCRIPTION +The +.Nm +driver provides the system the ability to read the digital temperature +sensor found on several Intel platform controller hub (PCH) chipsets. +The following chipsets are supported which cover most Intel Core familiy +(non-Atom) CPUs starting with the Haswell generation: +.Bl -dash +.It +Intel 8 Series / C220 Series Chipset Platform Controller Hub +.It +Intel 9 Series Chipset Family Platform Controller Hub +.It +Intel C610 Series Chipset and X99 Chipset Platform Controller Hub +.It +Intel 100 Series Chipset Family Platform Controller Hub +.It +Intel C620 Series Chipset Platform Controller Hub +.It +Intel 200 and Z370 Series Chipset Families Platform Controller Hub +.It +Intel 7th/8th Generation Processor Family U/Y Platforms +.It +Intel 300 Series and Intel C240 Series Chipset Family Platform +Controller Hub +.El +.Pp +Temperature information is available to the system via the fault +management architecture +.Pq FMA . +The file system location and programming interface to the +.Nm +driver are considered +.Sy Volatile , +subject to change without notice, and should not be used directly. +Raw temperature information can be dumped through the FMA developer +utility +.Sy fmtopo . +.Sh SEE ALSO +.Xr fmadm 1M +.Rs +.%A Intel Corporation +.%B Intel 300 Series and Intel C240 Series Chipset Family Platform Controller Hub +.%D March 2019 +.%O Document Number 337347-005 +.%V 1 +.%U https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/300-series-chipset-pch-datasheet-vol-1.pdf +.Re diff --git a/usr/src/pkg/manifests/driver-cpu-sensor.mf b/usr/src/pkg/manifests/driver-cpu-sensor.mf index 206456e092..b9161f82f6 100644 --- a/usr/src/pkg/manifests/driver-cpu-sensor.mf +++ b/usr/src/pkg/manifests/driver-cpu-sensor.mf @@ -33,11 +33,23 @@ driver name=amdf17nbdf \ alias=pci1022,1450 \ alias=pci1022,1460 driver name=coretemp +driver name=pchtemp \ + alias=pci8086,8c24 \ + alias=pci8086,8ca4 \ + alias=pci8086,8d24 \ + alias=pci8086,9d31 \ + alias=pci8086,a131 \ + alias=pci8086,a1b1 \ + alias=pci8086,a231 \ + alias=pci8086,a2b1 \ + alias=pci8086,a379 file path=kernel/drv/$(ARCH64)/amdf17nbdf group=sys file path=kernel/drv/$(ARCH64)/coretemp group=sys +file path=kernel/drv/$(ARCH64)/pchtemp group=sys file path=kernel/drv/coretemp.conf group=sys file path=usr/include/sys/sensors.h mode=0644 file path=usr/lib/devfsadm/linkmod/SUNW_sensor_link.so group=sys file path=usr/share/man/man7d/amdf17nbdf.7d file path=usr/share/man/man7d/coretemp.7d +file path=usr/share/man/man7d/pchtemp.7d license lic_CDDL license=lic_CDDL diff --git a/usr/src/pkg/manifests/service-fault-management.mf b/usr/src/pkg/manifests/service-fault-management.mf index 8e97ddca9e..a6e616605d 100644 --- a/usr/src/pkg/manifests/service-fault-management.mf +++ b/usr/src/pkg/manifests/service-fault-management.mf @@ -758,6 +758,8 @@ $(i386_ONLY)file \ $(i386_ONLY)file path=usr/platform/i86pc/lib/fm/topo/maps/psu-hc-topology.xml \ mode=0444 $(i386_ONLY)file path=usr/platform/i86pc/lib/fm/topo/plugins/chip.so mode=0555 +$(i386_ONLY)file path=usr/platform/i86pc/lib/fm/topo/plugins/chipset.so \ + mode=0555 $(i386_ONLY)file path=usr/platform/i86pc/lib/fm/topo/plugins/hostbridge.so \ mode=0555 $(i386_ONLY)file path=usr/platform/i86pc/lib/fm/topo/plugins/pcibus.so \ diff --git a/usr/src/uts/common/sys/sunddi.h b/usr/src/uts/common/sys/sunddi.h index 5a98e6e625..f81a391f41 100644 --- a/usr/src/uts/common/sys/sunddi.h +++ b/usr/src/uts/common/sys/sunddi.h @@ -24,7 +24,7 @@ * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. - * Copyright 2019, Joyent, Inc. + * Copyright 2019 Joyent, Inc. */ #ifndef _SYS_SUNDDI_H @@ -264,6 +264,7 @@ extern "C" { * Various device types used for sensors. */ #define DDI_NT_SENSOR_TEMP_CPU "ddi_sensor:temperature:cpu" +#define DDI_NT_SENSOR_TEMP_PCH "ddi_sensor:temperature:pch" /* * DDI event definitions diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index 2e38cfcab8..3f95d5d78a 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -21,7 +21,7 @@ # # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # Copyright 2018 Nexenta Systems, Inc. # @@ -337,3 +337,8 @@ CORETEMP_OBJS = coretemp.o # AMD Family 17 northbridge driver # AMDF17NBDF_OBJS = amdf17nbdf.o + +# +# Intel Platform Controller Hub Temperature Module +# +PCHTEMP_OBJS = pchtemp.o diff --git a/usr/src/uts/intel/Makefile.intel b/usr/src/uts/intel/Makefile.intel index 8e691a9d66..cbdcd84e7e 100644 --- a/usr/src/uts/intel/Makefile.intel +++ b/usr/src/uts/intel/Makefile.intel @@ -21,7 +21,7 @@ # # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2013 Andrew Stormont. All rights reserved. -# Copyright 2019, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # Copyright 2016 Garrett D'Amore <garrett@damore.org> # Copyright 2018 Nexenta Systems, Inc. # @@ -734,3 +734,4 @@ LINTFLAGS += -D_MACHDEP -I$(UTSBASE)/i86pc # DRV_KMODS += amdf17nbdf DRV_KMODS += coretemp +DRV_KMODS += pchtemp diff --git a/usr/src/uts/intel/Makefile.rules b/usr/src/uts/intel/Makefile.rules index 2e193a40fb..6993b7f605 100644 --- a/usr/src/uts/intel/Makefile.rules +++ b/usr/src/uts/intel/Makefile.rules @@ -182,6 +182,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/mc-amd/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/pchtemp/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/intel/io/pci/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) diff --git a/usr/src/uts/intel/io/pchtemp/pchtemp.c b/usr/src/uts/intel/io/pchtemp/pchtemp.c new file mode 100644 index 0000000000..2c2997c958 --- /dev/null +++ b/usr/src/uts/intel/io/pchtemp/pchtemp.c @@ -0,0 +1,525 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2019 Joyent, Inc. + */ + +/* + * Intel Platform Controller Hub (PCH) Thermal Sensor Driver + * + * The Intel PCH is a chip that was introduced around the Nehalem generation + * that provides many services for the broader system on a discrete chip from + * the CPU. While it existed prior to the Nehalem generation, it was previously + * two discrete chips called the Northbridge and Southbridge. Sometimes this + * device is also called a 'chipset'. + * + * The PCH contains everything from a USB controller, to an AHCI controller, to + * clocks, the Intel Management Engine, and more. Relevant to this driver is its + * thermal sensor which gives us the ability to read the temperature sensor that + * is embedded in the PCH. + * + * The format of this sensor varies based on the generation of the chipset. The + * current driver supports the following chipsets organized by datasheet, which + * corresponds with a change in format that was introduced in the Haswell + * generation: + * + * - Intel 8 Series PCH + * - Intel 9 Series PCH + * - Intel C610 Series and X99 PCH + * - Intel C620 Series PCH + * - Intel 100 Series PCH + * - Intel 200 Series and Z730 PCH + * - Intel Sunrise Point-LP (Kaby Lake-U) PCH + * - Intel 300 Series and C240 Chipset + * + * The following chipsets use a different format and are not currently + * supported: + * + * - Intel 5 Series and Xeon 3400 PCH + * - Intel 6 Series PCH + * - Intel 7 Series PCH + * - Intel C600 Series and X79 PCH + */ + +#include <sys/modctl.h> +#include <sys/conf.h> +#include <sys/devops.h> +#include <sys/types.h> +#include <sys/file.h> +#include <sys/open.h> +#include <sys/cred.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/cmn_err.h> +#include <sys/stat.h> +#include <sys/sensors.h> + +/* + * In all cases the data we care about is in the first PCI bar, bar 0. Per + * pci(4)/pcie(4), this is always going to be register number 1. + */ +#define PCHTEMP_RNUMBER 1 + +/* + * The PCH Temperature Sensor has a resolution of 1/2 a degree. This is a + * resolution of 2 in our parlance. The register reads 50 C higher than it is. + * Therefore our offset is 50 shifted over by one. + */ +#define PCHTEMP_TEMP_RESOLUTION 2 +#define PCHTEMP_TEMP_OFFSET (50 << 1) + +/* + * This register offset has the temperature that we want to read in the lower + * 8-bits. The resolution and offset are described above. + */ +#define PCHTEMP_REG_TEMP 0x00 +#define PCHTEMP_REG_TEMP_TSR 0x00ff + +/* + * Thermal Sensor Enable and Lock (TSEL) register. This register is a byte wide + * and has two bits that we care about. The ETS bit, enable thermal sensor, + * indicates whether or not the sensor is enabled. The control for this can be + * locked which is the PLDB, Policy Lock-Down Bit, bit. Which restricts + * additional control of this register. + */ +#define PCHTEMP_REG_TSEL 0x08 +#define PCHTEMP_REG_TSEL_ETS 0x01 +#define PCHTEMP_REG_TSEL_PLDB 0x80 + +/* + * Threshold registers for the thermal sensors. These indicate the catastrophic, + * the high alert threshold, and the low alert threshold respectively. + */ +#define PCHTEMP_REG_CTT 0x10 +#define PCHTEMP_REG_TAHV 0x14 +#define PCHTEMP_REG_TALV 0x18 + +typedef struct pchtemp { + dev_info_t *pcht_dip; + int pcht_fm_caps; + caddr_t pcht_base; + ddi_acc_handle_t pcht_handle; + kmutex_t pcht_mutex; /* Protects members below */ + uint16_t pcht_temp_raw; + uint8_t pcht_tsel_raw; + uint16_t pcht_ctt_raw; + uint16_t pcht_tahv_raw; + uint16_t pcht_talv_raw; + int64_t pcht_temp; +} pchtemp_t; + +void *pchtemp_state; + +static pchtemp_t * +pchtemp_find_by_dev(dev_t dev) +{ + return (ddi_get_soft_state(pchtemp_state, getminor(dev))); +} + +static int +pchtemp_read_check(pchtemp_t *pch) +{ + ddi_fm_error_t de; + + if (!DDI_FM_ACC_ERR_CAP(pch->pcht_fm_caps)) { + return (DDI_FM_OK); + } + + ddi_fm_acc_err_get(pch->pcht_handle, &de, DDI_FME_VERSION); + ddi_fm_acc_err_clear(pch->pcht_handle, DDI_FME_VERSION); + return (de.fme_status); +} + +static int +pchtemp_read(pchtemp_t *pch) +{ + uint16_t temp, ctt, tahv, talv; + uint8_t tsel; + + ASSERT(MUTEX_HELD(&pch->pcht_mutex)); + + temp = ddi_get16(pch->pcht_handle, + (uint16_t *)((uintptr_t)pch->pcht_base + PCHTEMP_REG_TEMP)); + tsel = ddi_get8(pch->pcht_handle, + (uint8_t *)((uintptr_t)pch->pcht_base + PCHTEMP_REG_TSEL)); + ctt = ddi_get16(pch->pcht_handle, + (uint16_t *)((uintptr_t)pch->pcht_base + PCHTEMP_REG_CTT)); + tahv = ddi_get16(pch->pcht_handle, + (uint16_t *)((uintptr_t)pch->pcht_base + PCHTEMP_REG_TAHV)); + talv = ddi_get16(pch->pcht_handle, + (uint16_t *)((uintptr_t)pch->pcht_base + PCHTEMP_REG_TALV)); + + if (pchtemp_read_check(pch) != DDI_FM_OK) { + dev_err(pch->pcht_dip, CE_WARN, "failed to read temperature " + "data due to FM device error"); + return (EIO); + } + + pch->pcht_temp_raw = temp; + pch->pcht_tsel_raw = tsel; + pch->pcht_ctt_raw = ctt; + pch->pcht_tahv_raw = tahv; + pch->pcht_talv_raw = talv; + + if ((tsel & PCHTEMP_REG_TSEL_ETS) == 0) { + return (ENXIO); + } + + pch->pcht_temp = (temp & PCHTEMP_REG_TEMP_TSR) - PCHTEMP_TEMP_OFFSET; + + return (0); +} + +static int +pchtemp_open(dev_t *devp, int flags, int otype, cred_t *credp) +{ + pchtemp_t *pch; + + if (crgetzoneid(credp) != GLOBAL_ZONEID || drv_priv(credp)) { + return (EPERM); + } + + if ((flags & (FEXCL | FNDELAY | FWRITE)) != 0) { + return (EINVAL); + } + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + pch = pchtemp_find_by_dev(*devp); + if (pch == NULL) { + return (ENXIO); + } + + return (0); +} + +static int +pchtemp_ioctl_kind(intptr_t arg, int mode) +{ + sensor_ioctl_kind_t kind; + + bzero(&kind, sizeof (sensor_ioctl_kind_t)); + kind.sik_kind = SENSOR_KIND_TEMPERATURE; + + if (ddi_copyout((void *)&kind, (void *)arg, sizeof (kind), + mode & FKIOCTL) != 0) { + return (EFAULT); + } + + return (0); +} + +static int +pchtemp_ioctl_temp(pchtemp_t *pch, intptr_t arg, int mode) +{ + int ret; + sensor_ioctl_temperature_t temp; + + bzero(&temp, sizeof (temp)); + + mutex_enter(&pch->pcht_mutex); + if ((ret = pchtemp_read(pch)) != 0) { + mutex_exit(&pch->pcht_mutex); + return (ret); + } + + temp.sit_unit = SENSOR_UNIT_CELSIUS; + temp.sit_gran = PCHTEMP_TEMP_RESOLUTION; + temp.sit_temp = pch->pcht_temp; + mutex_exit(&pch->pcht_mutex); + + if (ddi_copyout(&temp, (void *)arg, sizeof (temp), + mode & FKIOCTL) != 0) { + return (EFAULT); + } + + return (0); +} + +static int +pchtemp_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, + int *rvalp) +{ + pchtemp_t *pch; + + pch = pchtemp_find_by_dev(dev); + if (pch == NULL) { + return (ENXIO); + } + + if ((mode & FREAD) == 0) { + return (EINVAL); + } + + switch (cmd) { + case SENSOR_IOCTL_TYPE: + return (pchtemp_ioctl_kind(arg, mode)); + case SENSOR_IOCTL_TEMPERATURE: + return (pchtemp_ioctl_temp(pch, arg, mode)); + default: + return (ENOTTY); + } +} + +static int +pchtemp_close(dev_t dev, int flags, int otype, cred_t *credp) +{ + return (0); +} + +static void +pchtemp_cleanup(pchtemp_t *pch) +{ + int inst; + + ASSERT3P(pch->pcht_dip, !=, NULL); + inst = ddi_get_instance(pch->pcht_dip); + + ddi_remove_minor_node(pch->pcht_dip, NULL); + + if (pch->pcht_handle != NULL) { + ddi_regs_map_free(&pch->pcht_handle); + } + + if (pch->pcht_fm_caps != DDI_FM_NOT_CAPABLE) { + ddi_fm_fini(pch->pcht_dip); + } + + mutex_destroy(&pch->pcht_mutex); + ddi_soft_state_free(pchtemp_state, inst); +} + +static int +pchtemp_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int inst, ret; + pchtemp_t *pch; + off_t memsize; + ddi_device_acc_attr_t da; + ddi_iblock_cookie_t iblk; + char name[1024]; + + switch (cmd) { + case DDI_RESUME: + return (DDI_SUCCESS); + case DDI_ATTACH: + break; + default: + return (DDI_FAILURE); + } + + inst = ddi_get_instance(dip); + if (ddi_soft_state_zalloc(pchtemp_state, inst) != DDI_SUCCESS) { + dev_err(dip, CE_WARN, "failed to allocate soft state entry %d", + inst); + return (DDI_FAILURE); + } + + pch = ddi_get_soft_state(pchtemp_state, inst); + if (pch == NULL) { + dev_err(dip, CE_WARN, "failed to retrieve soft state entry %d", + inst); + return (DDI_FAILURE); + } + pch->pcht_dip = dip; + + pch->pcht_fm_caps = DDI_FM_ACCCHK_CAPABLE; + ddi_fm_init(dip, &pch->pcht_fm_caps, &iblk); + + mutex_init(&pch->pcht_mutex, NULL, MUTEX_DRIVER, NULL); + + if (ddi_dev_regsize(dip, PCHTEMP_RNUMBER, &memsize) != DDI_SUCCESS) { + dev_err(dip, CE_WARN, "failed to obtain register size for " + "register set %d", PCHTEMP_RNUMBER); + goto err; + } + + bzero(&da, sizeof (ddi_device_acc_attr_t)); + da.devacc_attr_version = DDI_DEVICE_ATTR_V0; + da.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; + da.devacc_attr_dataorder = DDI_STRICTORDER_ACC; + + if (DDI_FM_ACC_ERR_CAP(pch->pcht_fm_caps)) { + da.devacc_attr_access = DDI_FLAGERR_ACC; + } else { + da.devacc_attr_access = DDI_DEFAULT_ACC; + } + + if ((ret = ddi_regs_map_setup(dip, PCHTEMP_RNUMBER, &pch->pcht_base, + 0, memsize, &da, &pch->pcht_handle)) != DDI_SUCCESS) { + dev_err(dip, CE_WARN, "failed to map register set %d: %d", + PCHTEMP_RNUMBER, ret); + goto err; + } + + if (snprintf(name, sizeof (name), "ts.%d", inst) >= sizeof (name)) { + dev_err(dip, CE_WARN, "failed to construct minor node name, " + "name too long"); + goto err; + } + + if (ddi_create_minor_node(pch->pcht_dip, name, S_IFCHR, (minor_t)inst, + DDI_NT_SENSOR_TEMP_PCH, 0) != DDI_SUCCESS) { + dev_err(dip, CE_WARN, "failed to create minor node %s", name); + goto err; + } + + /* + * Attempt a single read to lock in the temperature. We don't mind if + * this fails for some reason. + */ + mutex_enter(&pch->pcht_mutex); + (void) pchtemp_read(pch); + mutex_exit(&pch->pcht_mutex); + + return (DDI_SUCCESS); + +err: + pchtemp_cleanup(pch); + return (DDI_FAILURE); +} + +static int +pchtemp_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, + void **resultp) +{ + pchtemp_t *pch; + + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + pch = pchtemp_find_by_dev((dev_t)arg); + if (pch == NULL) { + return (DDI_FAILURE); + } + + *resultp = pch->pcht_dip; + break; + case DDI_INFO_DEVT2INSTANCE: + *resultp = (void *)(uintptr_t)getminor((dev_t)arg); + break; + default: + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +static int +pchtemp_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + int inst; + pchtemp_t *pch; + + switch (cmd) { + case DDI_DETACH: + break; + case DDI_SUSPEND: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + inst = ddi_get_instance(dip); + pch = ddi_get_soft_state(pchtemp_state, inst); + if (pch == NULL) { + dev_err(dip, CE_WARN, "asked to detached instance %d, but " + "it does not exist in soft state", inst); + return (DDI_FAILURE); + } + + pchtemp_cleanup(pch); + return (DDI_SUCCESS); +} + +static struct cb_ops pchtemp_cb_ops = { + .cb_open = pchtemp_open, + .cb_close = pchtemp_close, + .cb_strategy = nodev, + .cb_print = nodev, + .cb_dump = nodev, + .cb_read = nodev, + .cb_write = nodev, + .cb_ioctl = pchtemp_ioctl, + .cb_devmap = nodev, + .cb_mmap = nodev, + .cb_segmap = nodev, + .cb_chpoll = nochpoll, + .cb_prop_op = ddi_prop_op, + .cb_flag = D_MP, + .cb_rev = CB_REV, + .cb_aread = nodev, + .cb_awrite = nodev +}; + +static struct dev_ops pchtemp_dev_ops = { + .devo_rev = DEVO_REV, + .devo_refcnt = 0, + .devo_getinfo = pchtemp_getinfo, + .devo_identify = nulldev, + .devo_probe = nulldev, + .devo_attach = pchtemp_attach, + .devo_detach = pchtemp_detach, + .devo_reset = nodev, + .devo_power = ddi_power, + .devo_quiesce = ddi_quiesce_not_needed, + .devo_cb_ops = &pchtemp_cb_ops +}; + +static struct modldrv pchtemp_modldrv = { + .drv_modops = &mod_driverops, + .drv_linkinfo = "Intel PCH Thermal Sensor", + .drv_dev_ops = &pchtemp_dev_ops +}; + +static struct modlinkage pchtemp_modlinkage = { + .ml_rev = MODREV_1, + .ml_linkage = { &pchtemp_modldrv, NULL } +}; + +int +_init(void) +{ + int ret; + + if (ddi_soft_state_init(&pchtemp_state, sizeof (pchtemp_t), 1) != + DDI_SUCCESS) { + return (ENOMEM); + } + + if ((ret = mod_install(&pchtemp_modlinkage)) != 0) { + ddi_soft_state_fini(&pchtemp_state); + return (ret); + } + + return (ret); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&pchtemp_modlinkage, modinfop)); +} + +int +_fini(void) +{ + int ret; + + if ((ret = mod_remove(&pchtemp_modlinkage)) != 0) { + return (ret); + } + + ddi_soft_state_fini(&pchtemp_state); + return (ret); +} diff --git a/usr/src/uts/intel/pchtemp/Makefile b/usr/src/uts/intel/pchtemp/Makefile new file mode 100644 index 0000000000..9473aecceb --- /dev/null +++ b/usr/src/uts/intel/pchtemp/Makefile @@ -0,0 +1,46 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2019 Joyent, Inc. +# + +UTSBASE = ../.. + +MODULE = pchtemp +OBJECTS = $(PCHTEMP_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) + +include $(UTSBASE)/intel/Makefile.intel + +ALL_TARGET = $(BINARY) +LINT_TARGET = $(MODULE).lint +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +lint: $(LINT_DEPS) + +modlintlib: $(MODLINTLIB_DEPS) + +clean.lint: $(CLEAN_LINT_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/intel/Makefile.targ |