2019-05-20 15:18:57 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2009-12-17 04:38:25 +08:00
|
|
|
/*
|
2019-12-24 23:20:55 +08:00
|
|
|
* k10temp.c - AMD Family 10h/11h/12h/14h/15h/16h/17h
|
|
|
|
* processor hardware monitoring
|
2009-12-17 04:38:25 +08:00
|
|
|
*
|
|
|
|
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
|
2019-12-24 23:20:55 +08:00
|
|
|
* Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net>
|
2020-01-15 09:40:12 +08:00
|
|
|
*
|
|
|
|
* Implementation notes:
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
* - CCD register address information as well as the calculation to
|
2020-01-15 09:40:12 +08:00
|
|
|
* convert raw register values is from https://github.com/ocerman/zenpower.
|
|
|
|
* The information is not confirmed from chip datasheets, but experiments
|
|
|
|
* suggest that it provides reasonable temperature values.
|
2020-01-15 09:54:05 +08:00
|
|
|
* - Register addresses to read chip voltage and current are also from
|
|
|
|
* https://github.com/ocerman/zenpower, and not confirmed from chip
|
|
|
|
* datasheets. Current calibration is board specific and not typically
|
|
|
|
* shared by board vendors. For this reason, current values are
|
|
|
|
* normalized to report 1A/LSB for core current and and 0.25A/LSB for SoC
|
|
|
|
* current. Reported values can be adjusted using the sensors configuration
|
|
|
|
* file.
|
2009-12-17 04:38:25 +08:00
|
|
|
*/
|
|
|
|
|
2018-04-29 23:39:24 +08:00
|
|
|
#include <linux/bitops.h>
|
2020-01-22 13:33:54 +08:00
|
|
|
#include <linux/debugfs.h>
|
2009-12-17 04:38:25 +08:00
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/hwmon.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/pci.h>
|
2018-11-07 04:08:14 +08:00
|
|
|
#include <linux/pci_ids.h>
|
2018-05-05 04:01:33 +08:00
|
|
|
#include <asm/amd_nb.h>
|
2009-12-17 04:38:25 +08:00
|
|
|
#include <asm/processor.h>
|
|
|
|
|
2011-05-26 02:43:31 +08:00
|
|
|
MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
|
2009-12-17 04:38:25 +08:00
|
|
|
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
|
|
static bool force;
|
|
|
|
module_param(force, bool, 0444);
|
|
|
|
MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
|
|
|
|
|
2014-08-15 07:15:27 +08:00
|
|
|
/* Provide lock for writing to NB_SMU_IND_ADDR */
|
|
|
|
static DEFINE_MUTEX(nb_smu_ind_mutex);
|
|
|
|
|
2018-04-30 00:16:45 +08:00
|
|
|
#ifndef PCI_DEVICE_ID_AMD_15H_M70H_NB_F3
|
|
|
|
#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F3 0x15b3
|
|
|
|
#endif
|
|
|
|
|
2010-01-11 03:52:34 +08:00
|
|
|
/* CPUID function 0x80000001, ebx */
|
2018-04-29 23:39:24 +08:00
|
|
|
#define CPUID_PKGTYPE_MASK GENMASK(31, 28)
|
2010-01-11 03:52:34 +08:00
|
|
|
#define CPUID_PKGTYPE_F 0x00000000
|
|
|
|
#define CPUID_PKGTYPE_AM2R2_AM3 0x10000000
|
|
|
|
|
|
|
|
/* DRAM controller (PCI function 2) */
|
|
|
|
#define REG_DCT0_CONFIG_HIGH 0x094
|
2018-04-29 23:39:24 +08:00
|
|
|
#define DDR3_MODE BIT(8)
|
2010-01-11 03:52:34 +08:00
|
|
|
|
|
|
|
/* miscellaneous (PCI function 3) */
|
2009-12-17 04:38:25 +08:00
|
|
|
#define REG_HARDWARE_THERMAL_CONTROL 0x64
|
2018-04-29 23:39:24 +08:00
|
|
|
#define HTC_ENABLE BIT(0)
|
2009-12-17 04:38:25 +08:00
|
|
|
|
|
|
|
#define REG_REPORTED_TEMPERATURE 0xa4
|
|
|
|
|
|
|
|
#define REG_NORTHBRIDGE_CAPABILITIES 0xe8
|
2018-04-29 23:39:24 +08:00
|
|
|
#define NB_CAP_HTC BIT(10)
|
2009-12-17 04:38:25 +08:00
|
|
|
|
2014-08-15 07:15:27 +08:00
|
|
|
/*
|
2018-04-29 23:08:24 +08:00
|
|
|
* For F15h M60h and M70h, REG_HARDWARE_THERMAL_CONTROL
|
|
|
|
* and REG_REPORTED_TEMPERATURE have been moved to
|
|
|
|
* D0F0xBC_xD820_0C64 [Hardware Temperature Control]
|
|
|
|
* D0F0xBC_xD820_0CA4 [Reported Temperature Control]
|
2014-08-15 07:15:27 +08:00
|
|
|
*/
|
2018-04-29 23:08:24 +08:00
|
|
|
#define F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET 0xd8200c64
|
2014-08-15 07:15:27 +08:00
|
|
|
#define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
|
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
/* Common for Zen CPU families (Family 17h and 18h) */
|
|
|
|
#define ZEN_REPORTED_TEMP_CTRL_OFFSET 0x00059800
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
#define ZEN_CCD_TEMP(x) (0x00059954 + ((x) * 4))
|
|
|
|
#define ZEN_CCD_TEMP_VALID BIT(11)
|
|
|
|
#define ZEN_CCD_TEMP_MASK GENMASK(10, 0)
|
2017-09-05 09:33:53 +08:00
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
#define ZEN_CUR_TEMP_SHIFT 21
|
|
|
|
#define ZEN_CUR_TEMP_RANGE_SEL_MASK BIT(19)
|
2020-01-15 09:54:05 +08:00
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
#define ZEN_SVI_BASE 0x0005A000
|
2018-04-29 23:39:24 +08:00
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
/* F17h thermal registers through SMN */
|
|
|
|
#define F17H_M01H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0xc)
|
|
|
|
#define F17H_M01H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10)
|
2020-08-27 13:42:42 +08:00
|
|
|
#define F17H_M31H_SVI_TEL_PLANE0 (ZEN_SVI_BASE + 0x14)
|
|
|
|
#define F17H_M31H_SVI_TEL_PLANE1 (ZEN_SVI_BASE + 0x10)
|
2020-08-27 13:42:41 +08:00
|
|
|
|
2020-08-27 13:42:42 +08:00
|
|
|
#define F17H_M01H_CFACTOR_ICORE 1000000 /* 1A / LSB */
|
|
|
|
#define F17H_M01H_CFACTOR_ISOC 250000 /* 0.25A / LSB */
|
|
|
|
#define F17H_M31H_CFACTOR_ICORE 1000000 /* 1A / LSB */
|
|
|
|
#define F17H_M31H_CFACTOR_ISOC 310000 /* 0.31A / LSB */
|
2020-01-15 09:54:05 +08:00
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
struct k10temp_data {
|
|
|
|
struct pci_dev *pdev;
|
2018-04-29 23:08:24 +08:00
|
|
|
void (*read_htcreg)(struct pci_dev *pdev, u32 *regval);
|
2017-09-05 09:33:53 +08:00
|
|
|
void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
|
2017-09-05 09:33:53 +08:00
|
|
|
int temp_offset;
|
2018-04-24 21:55:55 +08:00
|
|
|
u32 temp_adjust_mask;
|
2020-01-24 00:58:22 +08:00
|
|
|
u32 show_temp;
|
2020-01-15 09:54:05 +08:00
|
|
|
u32 svi_addr[2];
|
2020-01-24 00:58:22 +08:00
|
|
|
bool is_zen;
|
2020-01-15 09:54:05 +08:00
|
|
|
bool show_current;
|
|
|
|
int cfactor[2];
|
2017-09-05 09:33:53 +08:00
|
|
|
};
|
|
|
|
|
2020-01-24 00:58:22 +08:00
|
|
|
#define TCTL_BIT 0
|
|
|
|
#define TDIE_BIT 1
|
|
|
|
#define TCCD_BIT(x) ((x) + 2)
|
|
|
|
|
|
|
|
#define HAVE_TEMP(d, channel) ((d)->show_temp & BIT(channel))
|
|
|
|
#define HAVE_TDIE(d) HAVE_TEMP(d, TDIE_BIT)
|
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
struct tctl_offset {
|
|
|
|
u8 model;
|
|
|
|
char const *id;
|
|
|
|
int offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct tctl_offset tctl_offset_table[] = {
|
2017-11-14 04:38:23 +08:00
|
|
|
{ 0x17, "AMD Ryzen 5 1600X", 20000 },
|
2017-09-05 09:33:53 +08:00
|
|
|
{ 0x17, "AMD Ryzen 7 1700X", 20000 },
|
|
|
|
{ 0x17, "AMD Ryzen 7 1800X", 20000 },
|
2018-04-24 21:55:55 +08:00
|
|
|
{ 0x17, "AMD Ryzen 7 2700X", 10000 },
|
2018-08-10 02:50:46 +08:00
|
|
|
{ 0x17, "AMD Ryzen Threadripper 19", 27000 }, /* 19{00,20,50}X */
|
|
|
|
{ 0x17, "AMD Ryzen Threadripper 29", 27000 }, /* 29{20,50,70,90}[W]X */
|
2017-09-05 09:33:53 +08:00
|
|
|
};
|
|
|
|
|
2020-01-15 09:54:05 +08:00
|
|
|
static bool is_threadripper(void)
|
|
|
|
{
|
|
|
|
return strstr(boot_cpu_data.x86_model_id, "Threadripper");
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool is_epyc(void)
|
|
|
|
{
|
|
|
|
return strstr(boot_cpu_data.x86_model_id, "EPYC");
|
|
|
|
}
|
|
|
|
|
2018-04-29 23:08:24 +08:00
|
|
|
static void read_htcreg_pci(struct pci_dev *pdev, u32 *regval)
|
|
|
|
{
|
|
|
|
pci_read_config_dword(pdev, REG_HARDWARE_THERMAL_CONTROL, regval);
|
|
|
|
}
|
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
|
|
|
|
{
|
|
|
|
pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
|
|
|
|
unsigned int base, int offset, u32 *val)
|
2014-08-15 07:15:27 +08:00
|
|
|
{
|
|
|
|
mutex_lock(&nb_smu_ind_mutex);
|
|
|
|
pci_bus_write_config_dword(pdev->bus, devfn,
|
2017-09-05 09:33:53 +08:00
|
|
|
base, offset);
|
2014-08-15 07:15:27 +08:00
|
|
|
pci_bus_read_config_dword(pdev->bus, devfn,
|
2017-09-05 09:33:53 +08:00
|
|
|
base + 4, val);
|
2014-08-15 07:15:27 +08:00
|
|
|
mutex_unlock(&nb_smu_ind_mutex);
|
|
|
|
}
|
|
|
|
|
2018-04-29 23:08:24 +08:00
|
|
|
static void read_htcreg_nb_f15(struct pci_dev *pdev, u32 *regval)
|
|
|
|
{
|
|
|
|
amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
|
|
|
|
F15H_M60H_HARDWARE_TEMP_CTRL_OFFSET, regval);
|
|
|
|
}
|
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
|
|
|
|
{
|
|
|
|
amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
|
|
|
|
F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
|
|
|
|
}
|
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
static void read_tempreg_nb_zen(struct pci_dev *pdev, u32 *regval)
|
2017-09-05 09:33:53 +08:00
|
|
|
{
|
2018-05-05 04:01:33 +08:00
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(pdev),
|
2020-08-27 13:42:41 +08:00
|
|
|
ZEN_REPORTED_TEMP_CTRL_OFFSET, regval);
|
2017-09-05 09:33:53 +08:00
|
|
|
}
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
static long get_raw_temp(struct k10temp_data *data)
|
2009-12-17 04:38:25 +08:00
|
|
|
{
|
2018-04-27 03:22:29 +08:00
|
|
|
u32 regval;
|
2019-12-24 23:20:55 +08:00
|
|
|
long temp;
|
2017-09-05 09:33:53 +08:00
|
|
|
|
|
|
|
data->read_tempreg(data->pdev, ®val);
|
2020-08-27 13:42:41 +08:00
|
|
|
temp = (regval >> ZEN_CUR_TEMP_SHIFT) * 125;
|
2018-04-24 21:55:55 +08:00
|
|
|
if (regval & data->temp_adjust_mask)
|
|
|
|
temp -= 49000;
|
2018-04-27 03:22:29 +08:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2020-04-09 16:45:02 +08:00
|
|
|
static const char *k10temp_temp_label[] = {
|
2019-12-24 23:20:55 +08:00
|
|
|
"Tctl",
|
hwmon: (k10temp) Swap Tdie and Tctl on Family 17h CPUs
Traditionally, the temperature displayed by k10temp was Tctl.
On Family 17h CPUs, Tdie was displayed instead. To reduce confusion,
Tctl was added later as second temperature. This resulted in Tdie
being reported as temp1_input, and Tctl as temp2_input. This is
different to non-Ryzen CPUs, where Tctl is displayed as temp1_input.
Swap temp1_input and temp2_input on Family 17h CPUs, such that Tctl
is now reported as temp1_input and Tdie is reported as temp2_input,
to align with other CPUs, streamline the code, and make it less
confusing. Coincidentally, this also aligns the code with its
documentation, which states that Tdie is reported as temp2_input.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 23:57:09 +08:00
|
|
|
"Tdie",
|
2020-01-15 09:40:12 +08:00
|
|
|
"Tccd1",
|
|
|
|
"Tccd2",
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
"Tccd3",
|
|
|
|
"Tccd4",
|
|
|
|
"Tccd5",
|
|
|
|
"Tccd6",
|
|
|
|
"Tccd7",
|
|
|
|
"Tccd8",
|
2019-12-24 23:20:55 +08:00
|
|
|
};
|
2018-04-27 03:22:29 +08:00
|
|
|
|
2020-04-09 16:45:02 +08:00
|
|
|
static const char *k10temp_in_label[] = {
|
2020-01-15 09:54:05 +08:00
|
|
|
"Vcore",
|
|
|
|
"Vsoc",
|
|
|
|
};
|
|
|
|
|
2020-04-09 16:45:02 +08:00
|
|
|
static const char *k10temp_curr_label[] = {
|
2020-01-15 09:54:05 +08:00
|
|
|
"Icore",
|
|
|
|
"Isoc",
|
|
|
|
};
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
static int k10temp_read_labels(struct device *dev,
|
|
|
|
enum hwmon_sensor_types type,
|
|
|
|
u32 attr, int channel, const char **str)
|
2009-12-17 04:38:25 +08:00
|
|
|
{
|
2020-01-15 09:54:05 +08:00
|
|
|
switch (type) {
|
|
|
|
case hwmon_temp:
|
|
|
|
*str = k10temp_temp_label[channel];
|
|
|
|
break;
|
|
|
|
case hwmon_in:
|
|
|
|
*str = k10temp_in_label[channel];
|
|
|
|
break;
|
|
|
|
case hwmon_curr:
|
|
|
|
*str = k10temp_curr_label[channel];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2019-12-24 23:20:55 +08:00
|
|
|
return 0;
|
2009-12-17 04:38:25 +08:00
|
|
|
}
|
|
|
|
|
2020-01-15 09:54:05 +08:00
|
|
|
static int k10temp_read_curr(struct device *dev, u32 attr, int channel,
|
|
|
|
long *val)
|
|
|
|
{
|
|
|
|
struct k10temp_data *data = dev_get_drvdata(dev);
|
|
|
|
u32 regval;
|
|
|
|
|
|
|
|
switch (attr) {
|
|
|
|
case hwmon_curr_input:
|
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
|
|
|
|
data->svi_addr[channel], ®val);
|
|
|
|
*val = DIV_ROUND_CLOSEST(data->cfactor[channel] *
|
|
|
|
(regval & 0xff),
|
|
|
|
1000);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int k10temp_read_in(struct device *dev, u32 attr, int channel, long *val)
|
|
|
|
{
|
|
|
|
struct k10temp_data *data = dev_get_drvdata(dev);
|
|
|
|
u32 regval;
|
|
|
|
|
|
|
|
switch (attr) {
|
|
|
|
case hwmon_in_input:
|
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
|
|
|
|
data->svi_addr[channel], ®val);
|
|
|
|
regval = (regval >> 16) & 0xff;
|
|
|
|
*val = DIV_ROUND_CLOSEST(155000 - regval * 625, 100);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int k10temp_read_temp(struct device *dev, u32 attr, int channel,
|
|
|
|
long *val)
|
2009-12-17 04:38:25 +08:00
|
|
|
{
|
2017-09-05 09:33:53 +08:00
|
|
|
struct k10temp_data *data = dev_get_drvdata(dev);
|
2009-12-17 04:38:25 +08:00
|
|
|
u32 regval;
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
switch (attr) {
|
|
|
|
case hwmon_temp_input:
|
|
|
|
switch (channel) {
|
hwmon: (k10temp) Swap Tdie and Tctl on Family 17h CPUs
Traditionally, the temperature displayed by k10temp was Tctl.
On Family 17h CPUs, Tdie was displayed instead. To reduce confusion,
Tctl was added later as second temperature. This resulted in Tdie
being reported as temp1_input, and Tctl as temp2_input. This is
different to non-Ryzen CPUs, where Tctl is displayed as temp1_input.
Swap temp1_input and temp2_input on Family 17h CPUs, such that Tctl
is now reported as temp1_input and Tdie is reported as temp2_input,
to align with other CPUs, streamline the code, and make it less
confusing. Coincidentally, this also aligns the code with its
documentation, which states that Tdie is reported as temp2_input.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 23:57:09 +08:00
|
|
|
case 0: /* Tctl */
|
|
|
|
*val = get_raw_temp(data);
|
2019-12-24 23:20:55 +08:00
|
|
|
if (*val < 0)
|
|
|
|
*val = 0;
|
|
|
|
break;
|
hwmon: (k10temp) Swap Tdie and Tctl on Family 17h CPUs
Traditionally, the temperature displayed by k10temp was Tctl.
On Family 17h CPUs, Tdie was displayed instead. To reduce confusion,
Tctl was added later as second temperature. This resulted in Tdie
being reported as temp1_input, and Tctl as temp2_input. This is
different to non-Ryzen CPUs, where Tctl is displayed as temp1_input.
Swap temp1_input and temp2_input on Family 17h CPUs, such that Tctl
is now reported as temp1_input and Tdie is reported as temp2_input,
to align with other CPUs, streamline the code, and make it less
confusing. Coincidentally, this also aligns the code with its
documentation, which states that Tdie is reported as temp2_input.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 23:57:09 +08:00
|
|
|
case 1: /* Tdie */
|
|
|
|
*val = get_raw_temp(data) - data->temp_offset;
|
2019-12-24 23:20:55 +08:00
|
|
|
if (*val < 0)
|
|
|
|
*val = 0;
|
|
|
|
break;
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
case 2 ... 9: /* Tccd{1-8} */
|
2020-01-15 09:40:12 +08:00
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
|
2020-08-27 13:42:41 +08:00
|
|
|
ZEN_CCD_TEMP(channel - 2), ®val);
|
|
|
|
*val = (regval & ZEN_CCD_TEMP_MASK) * 125 - 49000;
|
2020-01-15 09:40:12 +08:00
|
|
|
break;
|
2019-12-24 23:20:55 +08:00
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case hwmon_temp_max:
|
|
|
|
*val = 70 * 1000;
|
|
|
|
break;
|
|
|
|
case hwmon_temp_crit:
|
|
|
|
data->read_htcreg(data->pdev, ®val);
|
|
|
|
*val = ((regval >> 16) & 0x7f) * 500 + 52000;
|
|
|
|
break;
|
|
|
|
case hwmon_temp_crit_hyst:
|
|
|
|
data->read_htcreg(data->pdev, ®val);
|
|
|
|
*val = (((regval >> 16) & 0x7f)
|
|
|
|
- ((regval >> 24) & 0xf)) * 500 + 52000;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
return 0;
|
2009-12-17 04:38:25 +08:00
|
|
|
}
|
|
|
|
|
2020-01-15 09:54:05 +08:00
|
|
|
static int k10temp_read(struct device *dev, enum hwmon_sensor_types type,
|
|
|
|
u32 attr, int channel, long *val)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case hwmon_temp:
|
|
|
|
return k10temp_read_temp(dev, attr, channel, val);
|
|
|
|
case hwmon_in:
|
|
|
|
return k10temp_read_in(dev, attr, channel, val);
|
|
|
|
case hwmon_curr:
|
|
|
|
return k10temp_read_curr(dev, attr, channel, val);
|
|
|
|
default:
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
static umode_t k10temp_is_visible(const void *_data,
|
|
|
|
enum hwmon_sensor_types type,
|
|
|
|
u32 attr, int channel)
|
2014-08-16 00:27:03 +08:00
|
|
|
{
|
2019-12-24 23:20:55 +08:00
|
|
|
const struct k10temp_data *data = _data;
|
2017-09-05 09:33:53 +08:00
|
|
|
struct pci_dev *pdev = data->pdev;
|
2018-04-27 03:22:29 +08:00
|
|
|
u32 reg;
|
2014-08-16 00:27:03 +08:00
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
switch (type) {
|
|
|
|
case hwmon_temp:
|
|
|
|
switch (attr) {
|
|
|
|
case hwmon_temp_input:
|
2020-01-24 00:58:22 +08:00
|
|
|
if (!HAVE_TEMP(data, channel))
|
2019-12-24 23:20:55 +08:00
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case hwmon_temp_max:
|
2020-01-24 00:58:22 +08:00
|
|
|
if (channel || data->is_zen)
|
2019-12-24 23:20:55 +08:00
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case hwmon_temp_crit:
|
|
|
|
case hwmon_temp_crit_hyst:
|
|
|
|
if (channel || !data->read_htcreg)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pci_read_config_dword(pdev,
|
|
|
|
REG_NORTHBRIDGE_CAPABILITIES,
|
|
|
|
®);
|
|
|
|
if (!(reg & NB_CAP_HTC))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
data->read_htcreg(data->pdev, ®);
|
|
|
|
if (!(reg & HTC_ENABLE))
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case hwmon_temp_label:
|
2020-01-24 00:58:22 +08:00
|
|
|
/* Show temperature labels only on Zen CPUs */
|
|
|
|
if (!data->is_zen || !HAVE_TEMP(data, channel))
|
2020-01-15 09:40:12 +08:00
|
|
|
return 0;
|
2019-12-24 23:20:55 +08:00
|
|
|
break;
|
|
|
|
default:
|
2018-04-27 03:22:29 +08:00
|
|
|
return 0;
|
2019-12-24 23:20:55 +08:00
|
|
|
}
|
2018-04-27 03:22:29 +08:00
|
|
|
break;
|
2020-01-15 09:54:05 +08:00
|
|
|
case hwmon_in:
|
|
|
|
case hwmon_curr:
|
|
|
|
if (!data->show_current)
|
|
|
|
return 0;
|
|
|
|
break;
|
2019-12-24 23:20:55 +08:00
|
|
|
default:
|
|
|
|
return 0;
|
2014-08-16 00:27:03 +08:00
|
|
|
}
|
2019-12-24 23:20:55 +08:00
|
|
|
return 0444;
|
2014-08-16 00:27:03 +08:00
|
|
|
}
|
|
|
|
|
2012-11-20 02:22:35 +08:00
|
|
|
static bool has_erratum_319(struct pci_dev *pdev)
|
2009-12-17 04:38:25 +08:00
|
|
|
{
|
2010-01-11 03:52:34 +08:00
|
|
|
u32 pkg_type, reg_dram_cfg;
|
|
|
|
|
|
|
|
if (boot_cpu_data.x86 != 0x10)
|
|
|
|
return false;
|
|
|
|
|
2009-12-17 04:38:25 +08:00
|
|
|
/*
|
2010-01-11 03:52:34 +08:00
|
|
|
* Erratum 319: The thermal sensor of Socket F/AM2+ processors
|
|
|
|
* may be unreliable.
|
2009-12-17 04:38:25 +08:00
|
|
|
*/
|
2010-01-11 03:52:34 +08:00
|
|
|
pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK;
|
|
|
|
if (pkg_type == CPUID_PKGTYPE_F)
|
|
|
|
return true;
|
|
|
|
if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3)
|
|
|
|
return false;
|
|
|
|
|
2010-06-20 15:22:31 +08:00
|
|
|
/* DDR3 memory implies socket AM3, which is good */
|
2010-01-11 03:52:34 +08:00
|
|
|
pci_bus_read_config_dword(pdev->bus,
|
|
|
|
PCI_DEVFN(PCI_SLOT(pdev->devfn), 2),
|
|
|
|
REG_DCT0_CONFIG_HIGH, ®_dram_cfg);
|
2010-06-20 15:22:31 +08:00
|
|
|
if (reg_dram_cfg & DDR3_MODE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Unfortunately it is possible to run a socket AM3 CPU with DDR2
|
|
|
|
* memory. We blacklist all the cores which do exist in socket AM2+
|
|
|
|
* format. It still isn't perfect, as RB-C2 cores exist in both AM2+
|
|
|
|
* and AM3 formats, but that's the best we can do.
|
|
|
|
*/
|
|
|
|
return boot_cpu_data.x86_model < 4 ||
|
2018-01-01 09:52:10 +08:00
|
|
|
(boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_stepping <= 2);
|
2009-12-17 04:38:25 +08:00
|
|
|
}
|
|
|
|
|
2020-01-22 13:33:54 +08:00
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
|
|
|
|
static void k10temp_smn_regs_show(struct seq_file *s, struct pci_dev *pdev,
|
|
|
|
u32 addr, int count)
|
|
|
|
{
|
|
|
|
u32 reg;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
if (!(i & 3))
|
|
|
|
seq_printf(s, "0x%06x: ", addr + i * 4);
|
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(pdev), addr + i * 4, ®);
|
|
|
|
seq_printf(s, "%08x ", reg);
|
|
|
|
if ((i & 3) == 3)
|
|
|
|
seq_puts(s, "\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int svi_show(struct seq_file *s, void *unused)
|
|
|
|
{
|
|
|
|
struct k10temp_data *data = s->private;
|
|
|
|
|
2020-08-27 13:42:41 +08:00
|
|
|
k10temp_smn_regs_show(s, data->pdev, ZEN_SVI_BASE, 32);
|
2020-01-22 13:33:54 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
DEFINE_SHOW_ATTRIBUTE(svi);
|
|
|
|
|
|
|
|
static int thm_show(struct seq_file *s, void *unused)
|
|
|
|
{
|
|
|
|
struct k10temp_data *data = s->private;
|
|
|
|
|
|
|
|
k10temp_smn_regs_show(s, data->pdev,
|
2020-08-27 13:42:41 +08:00
|
|
|
ZEN_REPORTED_TEMP_CTRL_OFFSET, 256);
|
2020-01-22 13:33:54 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
DEFINE_SHOW_ATTRIBUTE(thm);
|
|
|
|
|
|
|
|
static void k10temp_debugfs_cleanup(void *ddir)
|
|
|
|
{
|
|
|
|
debugfs_remove_recursive(ddir);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void k10temp_init_debugfs(struct k10temp_data *data)
|
|
|
|
{
|
|
|
|
struct dentry *debugfs;
|
|
|
|
char name[32];
|
|
|
|
|
|
|
|
/* Only show debugfs data for Family 17h/18h CPUs */
|
2020-01-24 00:58:22 +08:00
|
|
|
if (!data->is_zen)
|
2020-01-22 13:33:54 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
scnprintf(name, sizeof(name), "k10temp-%s", pci_name(data->pdev));
|
|
|
|
|
|
|
|
debugfs = debugfs_create_dir(name, NULL);
|
|
|
|
if (debugfs) {
|
|
|
|
debugfs_create_file("svi", 0444, debugfs, data, &svi_fops);
|
|
|
|
debugfs_create_file("thm", 0444, debugfs, data, &thm_fops);
|
|
|
|
devm_add_action_or_reset(&data->pdev->dev,
|
|
|
|
k10temp_debugfs_cleanup, debugfs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static void k10temp_init_debugfs(struct k10temp_data *data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
static const struct hwmon_channel_info *k10temp_info[] = {
|
|
|
|
HWMON_CHANNEL_INFO(temp,
|
|
|
|
HWMON_T_INPUT | HWMON_T_MAX |
|
|
|
|
HWMON_T_CRIT | HWMON_T_CRIT_HYST |
|
|
|
|
HWMON_T_LABEL,
|
2020-01-15 09:40:12 +08:00
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL,
|
2019-12-24 23:20:55 +08:00
|
|
|
HWMON_T_INPUT | HWMON_T_LABEL),
|
2020-01-15 09:54:05 +08:00
|
|
|
HWMON_CHANNEL_INFO(in,
|
|
|
|
HWMON_I_INPUT | HWMON_I_LABEL,
|
|
|
|
HWMON_I_INPUT | HWMON_I_LABEL),
|
|
|
|
HWMON_CHANNEL_INFO(curr,
|
|
|
|
HWMON_C_INPUT | HWMON_C_LABEL,
|
|
|
|
HWMON_C_INPUT | HWMON_C_LABEL),
|
2019-12-24 23:20:55 +08:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hwmon_ops k10temp_hwmon_ops = {
|
|
|
|
.is_visible = k10temp_is_visible,
|
|
|
|
.read = k10temp_read,
|
|
|
|
.read_string = k10temp_read_labels,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct hwmon_chip_info k10temp_chip_info = {
|
|
|
|
.ops = &k10temp_hwmon_ops,
|
|
|
|
.info = k10temp_info,
|
|
|
|
};
|
|
|
|
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
static void k10temp_get_ccd_support(struct pci_dev *pdev,
|
|
|
|
struct k10temp_data *data, int limit)
|
|
|
|
{
|
|
|
|
u32 regval;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < limit; i++) {
|
|
|
|
amd_smn_read(amd_pci_dev_to_node_id(pdev),
|
2020-08-27 13:42:41 +08:00
|
|
|
ZEN_CCD_TEMP(i), ®val);
|
|
|
|
if (regval & ZEN_CCD_TEMP_VALID)
|
2020-01-24 00:58:22 +08:00
|
|
|
data->show_temp |= BIT(TCCD_BIT(i));
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
2009-12-17 04:38:25 +08:00
|
|
|
{
|
2010-01-11 03:52:34 +08:00
|
|
|
int unreliable = has_erratum_319(pdev);
|
2014-08-16 00:27:03 +08:00
|
|
|
struct device *dev = &pdev->dev;
|
2017-09-05 09:33:53 +08:00
|
|
|
struct k10temp_data *data;
|
2014-08-16 00:27:03 +08:00
|
|
|
struct device *hwmon_dev;
|
2017-09-05 09:33:53 +08:00
|
|
|
int i;
|
2009-12-17 04:38:25 +08:00
|
|
|
|
2014-08-16 00:27:03 +08:00
|
|
|
if (unreliable) {
|
|
|
|
if (!force) {
|
|
|
|
dev_err(dev,
|
|
|
|
"unreliable CPU thermal sensor; monitoring disabled\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
dev_warn(dev,
|
2009-12-17 04:38:25 +08:00
|
|
|
"unreliable CPU thermal sensor; check erratum 319\n");
|
2014-08-16 00:27:03 +08:00
|
|
|
}
|
2009-12-17 04:38:25 +08:00
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
data->pdev = pdev;
|
2020-01-24 00:58:22 +08:00
|
|
|
data->show_temp |= BIT(TCTL_BIT); /* Always show Tctl */
|
2017-09-05 09:33:53 +08:00
|
|
|
|
2018-09-03 03:02:53 +08:00
|
|
|
if (boot_cpu_data.x86 == 0x15 &&
|
|
|
|
((boot_cpu_data.x86_model & 0xf0) == 0x60 ||
|
|
|
|
(boot_cpu_data.x86_model & 0xf0) == 0x70)) {
|
2018-04-29 23:08:24 +08:00
|
|
|
data->read_htcreg = read_htcreg_nb_f15;
|
2017-09-05 09:33:53 +08:00
|
|
|
data->read_tempreg = read_tempreg_nb_f15;
|
2018-12-08 14:33:28 +08:00
|
|
|
} else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
|
2020-08-27 13:42:41 +08:00
|
|
|
data->temp_adjust_mask = ZEN_CUR_TEMP_RANGE_SEL_MASK;
|
|
|
|
data->read_tempreg = read_tempreg_nb_zen;
|
2020-01-24 00:58:22 +08:00
|
|
|
data->show_temp |= BIT(TDIE_BIT); /* show Tdie */
|
|
|
|
data->is_zen = true;
|
2020-01-15 09:40:12 +08:00
|
|
|
|
|
|
|
switch (boot_cpu_data.x86_model) {
|
|
|
|
case 0x1: /* Zen */
|
|
|
|
case 0x8: /* Zen+ */
|
|
|
|
case 0x11: /* Zen APU */
|
|
|
|
case 0x18: /* Zen+ APU */
|
2020-01-15 09:54:05 +08:00
|
|
|
data->show_current = !is_threadripper() && !is_epyc();
|
|
|
|
data->svi_addr[0] = F17H_M01H_SVI_TEL_PLANE0;
|
|
|
|
data->svi_addr[1] = F17H_M01H_SVI_TEL_PLANE1;
|
2020-08-27 13:42:42 +08:00
|
|
|
data->cfactor[0] = F17H_M01H_CFACTOR_ICORE;
|
|
|
|
data->cfactor[1] = F17H_M01H_CFACTOR_ISOC;
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
k10temp_get_ccd_support(pdev, data, 4);
|
2020-01-15 09:40:12 +08:00
|
|
|
break;
|
|
|
|
case 0x31: /* Zen2 Threadripper */
|
|
|
|
case 0x71: /* Zen2 */
|
2020-01-15 09:54:05 +08:00
|
|
|
data->show_current = !is_threadripper() && !is_epyc();
|
2020-08-27 13:42:42 +08:00
|
|
|
data->cfactor[0] = F17H_M31H_CFACTOR_ICORE;
|
|
|
|
data->cfactor[1] = F17H_M31H_CFACTOR_ISOC;
|
|
|
|
data->svi_addr[0] = F17H_M31H_SVI_TEL_PLANE0;
|
|
|
|
data->svi_addr[1] = F17H_M31H_SVI_TEL_PLANE1;
|
hwmon: (k10temp) Display up to eight sets of CCD temperatures
In HWiNFO, we see support for Tccd1, Tccd3, Tccd5, and Tccd7 temperature
sensors on Zen2 based Threadripper CPUs. Checking register maps on
Threadripper 3970X confirms SMN register addresses and values for those
sensors.
Register values observed in an idle system:
0x059950: 00000000 00000abc 00000000 00000ad8
0x059960: 00000000 00000ade 00000000 00000ae4
Under load:
0x059950: 00000000 00000c02 00000000 00000c14
0x059960: 00000000 00000c30 00000000 00000c22
More analysis shows that EPYC CPUs support up to 8 CCD temperature
sensors. EPYC 7601 supports three CCD temperature sensors. Unlike
Zen2 CPUs, the register space in Zen1 CPUs supports a maximum of four
sensors, so only search for a maximum of four sensors on Zen1 CPUs.
On top of that, in thm_10_0_sh_mask.h in the Linux kernel, we find
definitions for THM_DIE{1-3}_TEMP__VALID_MASK, set to 0x00000800, as well
as matching SMN addresses. This lets us conclude that bit 11 of the
respective registers is a valid bit. With this assumption, the temperature
offset is now 49 degrees C. This conveniently matches the documented
temperature offset for Tdie, again suggesting that above registers indeed
report temperatures sensor values. Assume that bit 11 is indeed a valid
bit, and add support for the additional sensors.
With this patch applied, output from 3970X (idle) looks as follows:
k10temp-pci-00c3
Adapter: PCI adapter
Tdie: +55.9°C
Tctl: +55.9°C
Tccd1: +39.8°C
Tccd3: +43.8°C
Tccd5: +43.8°C
Tccd7: +44.8°C
Tested-by: Michael Larabel <michael@phoronix.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2020-01-23 10:41:18 +08:00
|
|
|
k10temp_get_ccd_support(pdev, data, 8);
|
2020-01-15 09:40:12 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-04-24 21:55:55 +08:00
|
|
|
} else {
|
2018-04-29 23:08:24 +08:00
|
|
|
data->read_htcreg = read_htcreg_pci;
|
2017-09-05 09:33:53 +08:00
|
|
|
data->read_tempreg = read_tempreg_pci;
|
2018-04-24 21:55:55 +08:00
|
|
|
}
|
2017-09-05 09:33:53 +08:00
|
|
|
|
2017-09-05 09:33:53 +08:00
|
|
|
for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
|
|
|
|
const struct tctl_offset *entry = &tctl_offset_table[i];
|
|
|
|
|
|
|
|
if (boot_cpu_data.x86 == entry->model &&
|
|
|
|
strstr(boot_cpu_data.x86_model_id, entry->id)) {
|
|
|
|
data->temp_offset = entry->offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-24 23:20:55 +08:00
|
|
|
hwmon_dev = devm_hwmon_device_register_with_info(dev, "k10temp", data,
|
|
|
|
&k10temp_chip_info,
|
|
|
|
NULL);
|
2020-01-22 13:33:54 +08:00
|
|
|
if (IS_ERR(hwmon_dev))
|
|
|
|
return PTR_ERR(hwmon_dev);
|
|
|
|
|
|
|
|
k10temp_init_debugfs(data);
|
|
|
|
|
|
|
|
return 0;
|
2009-12-17 04:38:25 +08:00
|
|
|
}
|
|
|
|
|
2013-12-03 15:10:29 +08:00
|
|
|
static const struct pci_device_id k10temp_id_table[] = {
|
2009-12-17 04:38:25 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
|
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
|
2011-02-17 16:22:40 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
|
2011-05-26 02:43:31 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
|
2012-05-05 00:28:21 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
|
2014-01-15 02:46:46 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
|
2014-08-15 07:15:27 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
|
2018-04-30 00:16:45 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F3) },
|
2013-08-24 04:14:03 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
|
2014-03-12 05:25:59 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
|
2017-09-05 09:33:53 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
|
2018-05-05 04:01:33 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M10H_DF_F3) },
|
2018-11-07 04:08:21 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M30H_DF_F3) },
|
2020-05-11 04:48:41 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M60H_DF_F3) },
|
2019-07-23 01:46:53 +08:00
|
|
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_M70H_DF_F3) },
|
2018-12-08 14:33:28 +08:00
|
|
|
{ PCI_VDEVICE(HYGON, PCI_DEVICE_ID_AMD_17H_DF_F3) },
|
2009-12-17 04:38:25 +08:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(pci, k10temp_id_table);
|
|
|
|
|
|
|
|
static struct pci_driver k10temp_driver = {
|
|
|
|
.name = "k10temp",
|
|
|
|
.id_table = k10temp_id_table,
|
|
|
|
.probe = k10temp_probe,
|
|
|
|
};
|
|
|
|
|
2012-04-03 09:25:46 +08:00
|
|
|
module_pci_driver(k10temp_driver);
|