[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20200122160800.12560-4-linux@roeck-us.net>
Date: Wed, 22 Jan 2020 08:07:57 -0800
From: Guenter Roeck <linux@...ck-us.net>
To: linux-hwmon@...r.kernel.org
Cc: linux-kernel@...r.kernel.org, Clemens Ladisch <clemens@...isch.de>,
Jean Delvare <jdelvare@...e.com>,
Brad Campbell <lists2009@...rfbargle.com>,
Ondrej Čerman <ocerman@...1.eu>,
Bernhard Gebetsberger <bernhard.gebetsberger@....at>,
Holger Kiehl <Holger.Kiehl@....de>,
Michael Larabel <michael@...ronix.com>,
Jonathan McDowell <noodles@...th.li>,
Ken Moffat <zarniwhoop73@...glemail.com>,
Sebastian Reichel <sebastian.reichel@...labora.com>,
Darren Salt <devspam@...eofthesa.me.uk>,
Guenter Roeck <linux@...ck-us.net>
Subject: [PATCH v4 3/6] hwmon: (k10temp) Report temperatures per CPU die
Zen2 reports reporting temperatures per CPU die (called Core Complex Dies,
or CCD, by AMD). Add support for it to the k10temp driver.
Tested-by: Brad Campbell <lists2009@...rfbargle.com>
Tested-by: Bernhard Gebetsberger <bernhard.gebetsberger@....at>
Tested-by: Holger Kiehl <holger.kiehl@....de>
Tested-by: Michael Larabel <michael@...ronix.com>
Tested-by: Jonathan McDowell <noodles@...th.li>
Tested-by: Ken Moffat <zarniwhoop73@...glemail.com>
Tested-by: Darren Salt <devspam@...eofthesa.me.uk>
Signed-off-by: Guenter Roeck <linux@...ck-us.net>
---
drivers/hwmon/k10temp.c | 80 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 79 insertions(+), 1 deletion(-)
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index c45f6498a59b..0af096b061fa 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -5,6 +5,12 @@
*
* Copyright (c) 2009 Clemens Ladisch <clemens@...isch.de>
* Copyright (c) 2020 Guenter Roeck <linux@...ck-us.net>
+ *
+ * Implementation notes:
+ * - CCD1 and CCD2 register address information as well as the calculation to
+ * 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.
*/
#include <linux/bitops.h>
@@ -61,6 +67,8 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
/* F17h M01h Access througn SMN */
#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800
+#define F17H_M70H_CCD1_TEMP 0x00059954
+#define F17H_M70H_CCD2_TEMP 0x00059958
#define CUR_TEMP_SHIFT 21
#define CUR_TEMP_RANGE_SEL_MASK BIT(19)
@@ -72,6 +80,8 @@ struct k10temp_data {
int temp_offset;
u32 temp_adjust_mask;
bool show_tdie;
+ bool show_tccd1;
+ bool show_tccd2;
};
struct tctl_offset {
@@ -143,6 +153,8 @@ static long get_raw_temp(struct k10temp_data *data)
const char *k10temp_temp_label[] = {
"Tdie",
"Tctl",
+ "Tccd1",
+ "Tccd2",
};
static int k10temp_read_labels(struct device *dev,
@@ -172,6 +184,16 @@ static int k10temp_read(struct device *dev, enum hwmon_sensor_types type,
if (*val < 0)
*val = 0;
break;
+ case 2: /* Tccd1 */
+ amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
+ F17H_M70H_CCD1_TEMP, ®val);
+ *val = (regval & 0xfff) * 125 - 305000;
+ break;
+ case 3: /* Tccd2 */
+ amd_smn_read(amd_pci_dev_to_node_id(data->pdev),
+ F17H_M70H_CCD2_TEMP, ®val);
+ *val = (regval & 0xfff) * 125 - 305000;
+ break;
default:
return -EOPNOTSUPP;
}
@@ -206,8 +228,24 @@ static umode_t k10temp_is_visible(const void *_data,
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
- if (channel && !data->show_tdie)
+ switch (channel) {
+ case 0: /* Tdie, or Tctl if we don't show it */
+ break;
+ case 1: /* Tctl */
+ if (!data->show_tdie)
+ return 0;
+ break;
+ case 2: /* Tccd1 */
+ if (!data->show_tccd1)
+ return 0;
+ break;
+ case 3: /* Tccd2 */
+ if (!data->show_tccd2)
+ return 0;
+ break;
+ default:
return 0;
+ }
break;
case hwmon_temp_max:
if (channel)
@@ -229,8 +267,24 @@ static umode_t k10temp_is_visible(const void *_data,
return 0;
break;
case hwmon_temp_label:
+ /* No labels if we don't show the die temperature */
if (!data->show_tdie)
return 0;
+ switch (channel) {
+ case 0: /* Tdie */
+ case 1: /* Tctl */
+ break;
+ case 2: /* Tccd1 */
+ if (!data->show_tccd1)
+ return 0;
+ break;
+ case 3: /* Tccd2 */
+ if (!data->show_tccd2)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
break;
default:
return 0;
@@ -281,6 +335,8 @@ static const struct hwmon_channel_info *k10temp_info[] = {
HWMON_T_INPUT | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST |
HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
+ HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
NULL
};
@@ -326,9 +382,31 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
data->read_htcreg = read_htcreg_nb_f15;
data->read_tempreg = read_tempreg_nb_f15;
} else if (boot_cpu_data.x86 == 0x17 || boot_cpu_data.x86 == 0x18) {
+ u32 regval;
+
data->temp_adjust_mask = CUR_TEMP_RANGE_SEL_MASK;
data->read_tempreg = read_tempreg_nb_f17;
data->show_tdie = true;
+
+ switch (boot_cpu_data.x86_model) {
+ case 0x1: /* Zen */
+ case 0x8: /* Zen+ */
+ case 0x11: /* Zen APU */
+ case 0x18: /* Zen+ APU */
+ break;
+ case 0x31: /* Zen2 Threadripper */
+ case 0x71: /* Zen2 */
+ amd_smn_read(amd_pci_dev_to_node_id(pdev),
+ F17H_M70H_CCD1_TEMP, ®val);
+ if (regval & 0xfff)
+ data->show_tccd1 = true;
+
+ amd_smn_read(amd_pci_dev_to_node_id(pdev),
+ F17H_M70H_CCD2_TEMP, ®val);
+ if (regval & 0xfff)
+ data->show_tccd2 = true;
+ break;
+ }
} else {
data->read_htcreg = read_htcreg_pci;
data->read_tempreg = read_tempreg_pci;
--
2.17.1
Powered by blists - more mailing lists